/**
 * This class locally represents a sensor data item in the sensorbase.
 */
package org.hackystat.ui.sensordataviewer.server;

import java.util.ArrayList;

import javax.xml.datatype.XMLGregorianCalendar;

import org.hackystat.sensorbase.resource.sensordata.jaxb.Property;
import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;
import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorDataRef;
import org.hackystat.utilities.tstamp.Tstamp;

/**
 * This class represents a sensor data instance.
 * @author David J. Nickles
 *
 */
public class SensorDataItem {
  
  private long id;
  private ArrayList<String> root;
  private XMLGregorianCalendar timestamp;
  private XMLGregorianCalendar eventTimestamp;
  private XMLGregorianCalendar runtime;
  private XMLGregorianCalendar lastMod;
  private String type;
  private String tool;
  private String owner;
  private String resource;
  private String href;

  /**
   * Creates an empty, valid instance.
   */
  public SensorDataItem() {
    this.timestamp = Tstamp.makeTimestamp();
    this.id = this.timestamp.toGregorianCalendar().getTimeInMillis();
    this.eventTimestamp = makeEventTimestamp(this.timestamp);
    this.runtime = Tstamp.makeTimestamp();
    this.lastMod = Tstamp.makeTimestamp();
    this.type = "Type";
    this.tool = "Tool";
    this.owner = "Owner";
    this.resource = "Resource";
    this.href = "http://www.hackystat.org";
    this.root = new ArrayList<String>();
  }

  /**
   * Creates and initializes a sensor data instance from the returned RPC data.
   * @param ref A SensorDataRef object representing the attributes of a sensor data instance.
   */
  public SensorDataItem(SensorDataRef ref) {
    try {
      this.timestamp = ref.getTimestamp();
      this.id = this.timestamp.toGregorianCalendar().getTimeInMillis();
      this.eventTimestamp = makeEventTimestamp(this.timestamp);
      this.runtime = null;
      this.lastMod = ref.getLastMod();
      this.type = ref.getSensorDataType();
      this.tool = ref.getTool();
      this.owner = ref.getOwner();
      this.resource = null;
      this.href = ref.getHref();
      this.root = new ArrayList<String>();
      this.root.add(this.timestamp.toXMLFormat());
      this.root.add(this.type);
      this.root.add(this.tool);
      this.root.add(this.lastMod.toXMLFormat());
      this.root.add("Runtime=N/A");
      this.root.add("Resource=N/A");
      this.root.add(this.owner);
      this.root.add(this.href);
      this.root.add("Properties=N/A");
    } 
    catch (Exception e) {
      this.root.add(this.timestamp.toXMLFormat());
      this.root.add("Error");
      this.root.add("Sensorbase");
      this.root.add(Tstamp.makeTimestamp().toXMLFormat());
      this.root.add("Name=" + e.getClass().getCanonicalName());
      this.root.add("Message=" + e.getMessage());
    }
  }

  /**
   * Creates and initializes a sensor data instance from the returned RPC data.
   * @param sensordata object representing the attribute values of the sensor data item.
   */
  public SensorDataItem(SensorData sensordata) {
    this.timestamp = sensordata.getTimestamp();
    this.id = this.timestamp.toGregorianCalendar().getTimeInMillis();
    this.eventTimestamp = makeEventTimestamp(this.timestamp);
    this.runtime = sensordata.getRuntime();
    //this.lastMod = sensordata.getLastMod();
    this.owner = sensordata.getOwner();
    this.type = sensordata.getSensorDataType();
    this.tool = sensordata.getTool();
    this.resource = sensordata.getResource();
    this.href = "http://www.hackystat.org";
    this.root = new ArrayList<String>();
    this.root.add("Timestamp=" + this.timestamp.toXMLFormat());
    this.root.add(this.type);
    this.root.add(this.tool);
    //this.root.add("LastMod=" + this.lastMod.toXMLFormat());
    this.root.add("Runtime=" + this.runtime.toXMLFormat());
    this.root.add("Resource=" + this.resource);
    this.root.add("Owner=" + this.owner);
    for (Property p : sensordata.getProperties().getProperty()) {
      StringBuffer property = new StringBuffer();
      property.append(p.getKey());
      property.append('=');
      property.append(p.getValue());
      this.root.add(property.toString());
    }
  }
  
  /**
   * Takes the XMLGregorianCalendar and makes a copy and then zeros the seconds to round 
   * the timestamp down to the minute. This is the event timestamp.
   * @param cal an XMLGregorianCalendar timestamp.
   * @return the rounded timestamp
   */
  private XMLGregorianCalendar makeEventTimestamp(XMLGregorianCalendar cal) {
    XMLGregorianCalendar result = (XMLGregorianCalendar)cal.clone();
    result.setSecond(0);
    result.setMillisecond(0);
    return result;
  }
  
  /**
   * Gets a list of strings populated with the values of the sensor data.
   * @return list populated with the values of the sensor data
   */
  public ArrayList<String> getItem() {
    return this.root;
  }
  
  /**
   * Gets the event-timestamp property as an XMLGregorianCalendar.
   * @return the value of event-timestamp property
   */
  public XMLGregorianCalendar getEventTimestamp() {
    return this.eventTimestamp;
  }
  
  /**
   * Gets the event-timestamp property formatted to be an event header.
   * @return An XML formatted event-timestamp
   */
  public String formatEventTimestamp() {
    return SimpleDateFactories.getInstance().getHeaderfactory().format(
        this.eventTimestamp.toGregorianCalendar().getTime());
  }
  
  /**
   * Gets the value of the timestamp property.
   * @return the value of timestamp property
   */
  public XMLGregorianCalendar getTimestamp() {
    return this.timestamp;
  }
  
  /**
   * This method gets the value of the timestamp property as an XML formatted timestamp.
   * @return an XML formatted timestamp.
   */
  public String formatTimestamp() {
    return this.timestamp.toXMLFormat();
  }
  
  /**
   * Gets the value of the sensorDataType property.
   * @return the value of the type property
   */
  public String getType() {
    return this.type;
  }
  
  /**
   * Gets the value of the tool property.
   * @return the value of the tool property
   */
  public String getTool() {
    return this.tool;
  }
  
  /**
   * Gets the value of the href property.
   * @return the value of the href property
   */
  public String getHref() {
    return this.href;
  }

  /**
   * Gets the value of the unique id property.
   * @return a long unique id for this sensor data instance.
   */
  public long getID() {
    return this.id;
  }
  
  /**
   * <p>Indicates whether parameter <code>obj</code> is "equal to" this one.</p>
   * @param obj to compare.
   * @return <code>true</code> when <code>obj</code> is an instance of <code>SDVItem</code>
   *   and the SDVItems share the same value for their timestamp, otherwise <code>false</code>.
   * 
   * @throws NullPointerException If <code>obj</code> is <code>null</code>.
   */
  public boolean equals(Object obj) {
    if (obj == null) {
      throw new NullPointerException("Cannot test null for equality with this SDVItem");
    }
    boolean result = false;
    if (obj instanceof SensorDataItem) {
      result = (this.id == ((SensorDataItem)obj).getID());
    }
    return result;
  }
  
  /**
   * <p>Returns a hash code consistent with the definition of the equals method.</p>
   * @return hash code of this object.
   */
  public int hashCode() {
    return (int)this.id;
  }
}
